<?php
class User extends BaseEntity
{
    const SEED = 'numb!';

    //status
    const STATUS_UN_ACTIVATED = 0;
    const STATUS_VALID = 1;
    const STATUS_INVALID = 2;
    const STATUS_FREEZED = 3;

    protected $_name = 'user';
    protected $_primary = 'userId';

    protected $_userId;
    protected $_userName;
    protected $_password;
    protected $_seed;

    protected $_ip;
    protected $_status;

    static public function genEncryptInfo($password)
    {/*{{{*/
        ParamsChecker::requireNotNull($password, gettext('password'));

        $cryptInfo = array();
        $cryptInfo['seed'] = rand(1000000, 10000000);
        $cryptInfo["password"] =  md5($cryptInfo['seed'].self::SEED.$password); ;
        return $cryptInfo;
    }/*}}}*/

    public function createByBiz($userName, $password)
    {/*{{{*/
        ParamsChecker::requireNotNull($userName, gettext('userName'));
        ParamsChecker::requireNotNull($password, gettext('password'));
        
        $createTime = $lastModifyTime = date('Y-m-d H:i:s');
        $arr['id'] = self::createId();
        $arr['ver'] = self::INITIALIZED_VERSION;
        $arr['createTime'] = $createTime;
        $arr['lastModifyTime'] = $lastModifyTime;
        $arr['userId'] = self::createUserId();
        $arr['userName'] = $userName;

        $info = self::genEncryptInfo($password);
        $arr['password']= $info['password'];
        $arr['status'] = self::STATUS_UN_ACTIVATED;
        $arr['seed'] = $info['seed'];
        $arr['ip'] = ip2long(getenv('REMOTE_ADDR'));

        return $this->create($arr);
    }/*}}}*/

    public function ensureUserStatus()
    {/*{{{*/
        if (self::STATUS_VALID != $this->_status)
        {
            throw new UserException(UserException::USER_STATUS_INVALID);
        }
    }/*}}}*/

    static public function genAuthCrumb($userName)
    {/*{{{*/
        ParamsChecker::requireNotNull($userName, gettext('userName'));
        return substr(md5($userName.time()), 0, 6);
    }/*}}}*/

    //all setter MUST be declared! DO NOT assign it directly!
    public function setPassword($password)
    {/*{{{*/
        ParamsChecker::requireNotNull($password, gettext('password'));
        $info = self::genEncryptInfo($password);
        $this->_seed = $info['seed'];
        $this->_password = $info['password'];
    }/*}}}*/

    public function findByUserName($userName)
    {/*{{{*/
        ParamsChecker::requireNotNull($userName, gettext('userName'));
        $db = $this->getAdapter();
        $where = $db->quoteInto('userName = ?', $userName);
        return $this->fetchRow($where);
    }/*}}}*/

    public function authorize($userName, $password)
    {/*{{{*/
        ParamsChecker::requireNotNull($userName, gettext('userName'));
        ParamsChecker::requireNotNull($password, gettext('password'));
        $res = $this->findByUserName($userName);
        if (null != $res)
        {
            $arr = $res->toArray();
            self::validatePassword($password, $arr);
            return $res;
        }
        throw new UserException(UserException::USER_NOT_EXIST);
    }/*}}}*/

    protected function map()
    {/*{{{*/
        return array('userId', 'userName', 'password', 'status', 'seed', 'ip');
    }/*}}}*/

    static private function validatePassword($inputPass, $res, $expMsg=UserException::USER_PASSWORD_INVALID)
    {/*{{{*/
        ParamsChecker::requireNotNull($inputPass, gettext('password'));
        $seed = $res['seed'];
        $userPass = $res['password'];
        $encryptPass = md5($seed.self::SEED.$inputPass); ;
        if ($encryptPass != $userPass)
        {
            throw new UserException($expMsg);
        }
    }/*}}}*/
}
